package com.tencent.wxcloudrun.filter;

import com.alibaba.fastjson2.JSON;
import com.tencent.wxcloudrun.model.AdminUser;
import com.tencent.wxcloudrun.utils.JwtToken;
import com.tencent.wxcloudrun.utils.ThreadLocalTool;
import com.tencent.wxcloudrun.response.AppException;
import com.tencent.wxcloudrun.response.ErrorCodeMsgEnum;
import com.tencent.wxcloudrun.response.R;
import com.tencent.wxcloudrun.service.AdminUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * ClassName: RequestFilter
 * Package: com.tencent.wxcloudrun.RequestFilter
 * Description:
 *
 * @Date: 2023/1/23 6:41 PM
 * @Author: wht
 */
@Order(1)
@Slf4j
@WebFilter(filterName = "MyFilter", urlPatterns = {"/*"})
//@Component
public class RequestFilter implements Filter {

    @Autowired
    private AdminUserService adminUserService;

    //路径匹配器，支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("----FilterDemo01过滤器初始化----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("请求--------------------------start");
        ThreadLocalTool.setCurrentTime();
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

//      跨域------------------------------------
        response.setHeader("Content-Type", "application/json; charset=utf-8");
//        这里最后要把*改成特定的域名？？？？？？？？？？？？？？？？
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE");
//        当一个http请求是复杂请求时，会先发送一个预检请求，目的是知道服务器是否支持这次请求（比如Access-Control-Allow-Origin、Access-Control-Allow-Methods）
//        Access-Control-Max-Age的作用：用于指示预检请求（OPTIONS）的结果可以被缓存多长时间。它定义了在指定的时间内，浏览器可以重用预检请求的结果，而无需再次向服务器发起预检请求。这有助于减少跨域请求的延迟和服务器负载。
//        但是如果值设的特别大，则当服务器的Access-Control-Allow-Origin、Access-Control-Allow-Methods等改变时，客户端并不知情，因为客户端还在复用预检请求的结果。这样便造成了跨域请求的安全隐患
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");


//      判断本次请求是否需要处理。如果不需要处理，则直接放行---------------------
        String requestURI = request.getRequestURI();
        log.info("请求路径：" + requestURI);
        String[] urls = new String[]{"/admin/login", "/websocket/*"};
        if (check(urls, requestURI)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

//     从token中拿到userId，然后从数据库中获取用户信息，并保存到ThreadLocal中------------------------
        try {
            String token = request.getHeader("x-token");
            Integer userId = JwtToken.parseToken(token);
            if (userId == null) {
                throw new AppException(ErrorCodeMsgEnum.TOKEN_ERROR);
            }
            AdminUser adminUser = adminUserService.getById(userId);
            if (adminUser == null) {
                throw new AppException(ErrorCodeMsgEnum.TOKEN_ERROR);
            }
//            把adminUser存入ThreadLocal中
            ThreadLocalTool.setUser(adminUser);
        } catch (Exception e) {
            response.getWriter().write(JSON.toJSONString(R.error(ErrorCodeMsgEnum.TOKEN_ERROR)));
            return;
        }


        filterChain.doFilter(servletRequest, servletResponse);

    }

    @Override
    public void destroy() {
        log.info("耗时:" + (System.currentTimeMillis() - ThreadLocalTool.getTime()));
        log.info("请求--------------------------end");
        ThreadLocalTool.remove();
    }

    /**
     * 路径匹配，检查本次请求是否需要放行
     *
     * @param urls
     * @param requestURI
     * @return
     */
    public static boolean check(String[] urls, String requestURI) {
        for (String url : urls) {
            if (PATH_MATCHER.match(url, requestURI)) {
                return true;
            }
        }
        return false;
    }
}
